package dt.inlee.common.tools;

import java.security.SecureRandom;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;


/**
 * Mac 计算
 * @author Administrator
 *
 */
public class MacUtil {
	
	/**
	 * Des检验字校验
	 * @param pDat  明文
	 * @param len   明文长度
	 * @param pKey  密钥 
	 * @param pMac  校验字
	 * @return  false:校验字错误   true:校验字通过
	 * @throws Exception
	 */
	public static boolean macDesExamine(byte[]pDat,int len,byte[] pKey,byte[] pMac) throws Exception{
		byte[] mac=getMacDesValues(pDat,len,pKey);
		String macString =byteArr2HexStr(mac);
		String pMacString=byteArr2HexStr(pMac);
		if(null !=mac && null!=pMac && pMacString.equals(macString)){
 
			return true; //检验字正确
		}else{
			 
		}
		return false;//检验字错误
	}
	
	/**
	 * 获得des加密校验字
	 * @param pDat  明文
	 * @param len   明文长度
	 * @param pKey  密钥 
	 * @return byte[] 4个字节校验字
	 * @throws Exception 
	 */
	public static byte[] getMacDesValues(byte[]pDat,int len,byte[] pKey) throws Exception{
		//获得默认的8个字节初始值
		byte[] buf={00,00,00,00,00,00,00,00};
		byte[] keyLeft=new byte[8];
		byte[] keyRight=new byte[8];
 
		System.arraycopy(pKey, 0, keyLeft, 0, 8);
		System.arraycopy(pKey, 8, keyRight, 0, 8);
 
		int jj=0;
		/**当明文长度大于8的时候，要将这个明文分成8字节一块进行异或处理*/
		while(len>=8){
			for(int index=0;index<8;index++){
				buf[index]^=pDat[jj+index];
			}
			buf=desEnCrypto(buf, keyLeft);
			len-=8;
			jj+=8;
		}
		/**最后一块，len=0的时候，最后块刚好为８字节，然后添加0x80与７个0的数据块做异或处理
		 * 如果小于8字节，else处需要重复补值，直至长度为8字节
		 * 
		 * */
		byte[] array2=new byte[8];
		System.arraycopy(buf, 0, array2, 0, 8);
		if(len==0){
			array2[0]^=0x80;
			for(int in=1;in<8;in++){
				array2[in]^=0x00;	
			}
		}else{
			int n;		
			for(n=0;n<len;n++){
				array2[n]^=pDat[jj+n];
			}
			if(len++<8){
				array2[n++]^=0x80;
			}
			while(len++<8){
				array2[n++]^=0x00;
			}
		}
		byte[] array=new byte[8];
		System.arraycopy(array2, 0, array, 0, 8);
 
		array2=desEnCrypto(array, keyLeft);
 
		System.arraycopy(array2, 0, array, 0, 8);
		array2=desDeCrypt(array2, keyRight);
	    System.arraycopy(array2, 0, array, 0, 8);
		byte[] returnValue=new byte[4];
		System.arraycopy(desEnCrypto(array, keyLeft), 0, returnValue, 0, 4);
		
		return returnValue;
	}
	/**
	 * 将byte数组转换为表示16进制值的字符串
	 * 
	 * 
	 * @param arrB
	 *            需要转换的byte数组
	 * @return 转换后的字符串
	 * @throws Exception
	 *             本方法不处理任何异常，所有异常全部抛出
	 */
	public static String byteArr2HexStr(byte[] arrB) throws Exception {
		int iLen = arrB.length;
		// 每个byte用两个字符才能表示，所以字符串的长度是数组长度的两倍
		StringBuffer sb = new StringBuffer(iLen * 2);
		for (int i = 0; i < iLen; i++) {
			int intTmp = arrB[i];
			// 把负数转换为正数
			while (intTmp < 0) {
				intTmp = intTmp + 256;
			}
			// 小于0F的数需要在前面补0
			if (intTmp < 16) {
				sb.append("0");
			}
			sb.append(Integer.toString(intTmp, 16));
		}
		return sb.toString().toUpperCase();
	}
	
	/**
	 * Des加密
	 * 
	 * @param datasource
	 * @param key
	 * @return
	 */
	public static byte[] desEnCrypto(byte[] datasource, byte[] key) {
		try {
			SecureRandom random = new SecureRandom();
			DESKeySpec desKey = new DESKeySpec(key);
			// 创建一个密匙工厂，然后用它把DESKeySpec转换成
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");// DESede
																				// //DES/ECB/PKCS5Padding
			SecretKey securekey = keyFactory.generateSecret(desKey);
			// Cipher对象实际完成加密操作
			Cipher cipher = Cipher.getInstance("DES");
			// 用密匙初始化Cipher对象
			cipher.init(Cipher.ENCRYPT_MODE, securekey, random);
			// 现在，获取数据并加密
			// 正式执行加密操作
			return cipher.doFinal(datasource);
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Des解密
	 * 
	 * @param src
	 * @param password
	 * @return
	 * @throws Exception
	 */
	public static byte[] desDeCrypt(byte[] src, byte[] key) throws Exception {
		// DES算法要求有一个可信任的随机数源
		SecureRandom random = new SecureRandom();
		// 创建一个DESKeySpec对象
		DESKeySpec desKey = new DESKeySpec(key);
		// 创建一个密匙工厂
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		// 将DESKeySpec对象转换成SecretKey对象
		SecretKey securekey = keyFactory.generateSecret(desKey);
		// Cipher对象实际完成解密操作
		Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
		// 用密匙初始化Cipher对象
		cipher.init(Cipher.DECRYPT_MODE, securekey, random);
		// 真正开始解密操作
		return cipher.doFinal(src);
	}
	/**
	 * 将表示16进制值的字符串转换为byte数组
	 * 
	 * @param strIn
	 *            需要转换的十六进制字符串
	 * @return 转换后的byte数组
	 * @throws Exception
	 *             本方法不处理任何异常，所有异常全部抛出
	 * 
	 */
	public static byte[] hexStr2ByteArr(String strIn) throws Exception {
		byte[] arrB = strIn.getBytes();
		int iLen = arrB.length;

		// 两个字符表示一个字节，所以字节数组长度是字符串长度除以2
		byte[] arrOut = new byte[iLen / 2];
		for (int i = 0; i < iLen; i = i + 2) {
			String strTmp = new String(arrB, i, 2);
			arrOut[i / 2] = (byte) Integer.parseInt(strTmp, 16);
		}
		return arrOut;
	}
	public static void main(String[] args) throws Exception {
		byte pDat[] = hexStr2ByteArr("00000019A00200000000200000000100000000000000001021");
//		byte pDat[] = {0x00, 0x00, 0x00 ,0x19 ,(byte) 0xA0 ,0x02 ,0x00, 0x00 ,0x00 ,0x00 ,0x20 ,0x00 ,0x00 ,0x00 ,0x01 ,0x00, 0x00, 0x00 ,0x00, 0x00, 0x00 ,0x00, 0x00 ,0x10 ,0x21};
		byte pKey[] = hexStr2ByteArr("31313131313131313131313131313131");
//		byte pKey[] = {0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31,0x31};
		byte kk[] = getMacDesValues(pDat, pDat.length, pKey);
		String str = byteArr2HexStr(kk);
		System.out.println(str);
	}
}
